#include "ViewerWidget.h"

#include <OWCommon/InitWindow.h>

CViewerWidget::CViewerWidget(void):
m_buttonMask(0), m_selectNode(NULL)
{
	m_coord.set(1.0f, 1.0f);

	CInitWindow initW(this, false);
	getCamera()->setClearColor(osg::Vec4f(0.5f, 0.5f, 0.5f, 1.0f));

	m_root = new osg::Group;
	m_house = new osg::MatrixTransform;
	//m_house->getOrCreateStateSet()->setMode(GL_LIGHTING, 0);

	osg::Program* progam = new osg::Program;
	osg::Shader* shader = new osg::Shader(osg::Shader::VERTEX);
	shader->loadShaderSourceFromFile("shader/vertex.vert");
	progam->addShader(shader);
	shader = new osg::Shader(osg::Shader::FRAGMENT);
	shader->loadShaderSourceFromFile("shader/frag.frag");
	progam->addShader(shader);
	m_house->getOrCreateStateSet()->setAttributeAndModes(progam);

	m_lightSor = new osg::LightSource;
	m_root->addChild(m_lightSor);

	m_root->addChild(m_house);
	setSceneData(m_root);

	initImage();
}


CViewerWidget::~CViewerWidget(void)
{
}

CViewerWidget* CViewerWidget::getSigleton()
{
	static CViewerWidget* sigleton = NULL;
	if (!sigleton)
	{
		sigleton = new CViewerWidget;
	}
	return sigleton;
}

void CViewerWidget::clearScene()
{
	m_house->removeChildren(0, m_house->getNumChildren());
}

void CViewerWidget::createScene( float l, float w, float h )
{
	float hL = l*0.5f, hW = w*0.5f;
	osg::Node* node = createPlane(osg::Vec3d(-hW, -hL, h), osg::Vec3d(hW, -hL, h), osg::Vec3d(-hW, hL, h));
	m_house->addChild(node);
	node = createPlane(osg::Vec3d(-hW, hL, 0.0), osg::Vec3d(hW, hL, 0.0), osg::Vec3d(-hW, -hL, 0.0));
	m_house->addChild(node);
	node = createPlane(osg::Vec3d(-hW, -hL, h), osg::Vec3d(-hW, hL, h), osg::Vec3d(-hW, -hL, 0.0));
	m_house->addChild(node);
	node = createPlane(osg::Vec3d(hW, hL, h), osg::Vec3d(hW, -hL, h), osg::Vec3d(hW, hL, 0.0));
	m_house->addChild(node);
	node = createPlane(osg::Vec3d(-hW, hL, h), osg::Vec3d(hW, hL, h), osg::Vec3d(-hW, hL, 0.0));
	m_house->addChild(node);

	m_lightSor->getLight()->setPosition(osg::Vec4f(-hW*0.4, -hL*0.4, h*0.5, 1.0));
	float radii = hL + h*0.5/tan(DegToRad(15.0));
	getCamera()->setViewMatrix(osg::Matrix::lookAt(osg::Vec3d(0.0, -radii, h*0.5), osg::Vec3d(0.0, 0.0, h*0.5), osg::Vec3d(0.0, 0.0, 1.0)));
	m_pitch = 0.0;
	m_yaw = 0.0;
	updateHouse();
}

std::string CViewerWidget::writeImageBuff(std::string name)
{
	osg::Image* img = new osg::Image(*m_pImageBuff);
	img->scaleImage(100, 100, 1);
	std::string tname = "houses/thumbnail/"+name+".jpg";
	osgDB::writeImageFile(*img, tname);
	img->releaseGLObjects();
	return tname;
}

void CViewerWidget::initImage()
{
	m_pImageBuff = new osg::Image;
	m_pImageBuff->setPixelFormat(GL_RGB);
	getCamera()->attach(osg::Camera::COLOR_BUFFER0, m_pImageBuff);
}

osg::Node* CViewerWidget::createPlane( const osg::Vec3d& p1, const osg::Vec3d& p2, const osg::Vec3d& p3, unsigned int row /*= 10*/ )
{
	osg::Vec3Array* vertexs = new osg::Vec3Array;
	osg::Vec4Array* colors = new osg::Vec4Array;
	osg::Vec2Array* coords = new osg::Vec2Array;
	osg::Vec3Array* normals = new osg::Vec3Array;

	osg::Vec3d sDir = p2 - p1, tDir = p3 - p1;
	float uCoord = 1.0/row;
	sDir *= uCoord;
	tDir *= uCoord;
	for (unsigned int i = 0; i < row; i++)
	{
		for (unsigned int j = 0; j <= row; j++)
		{
			unsigned int tJ = j;
			if (tJ%2 != 0)
				tJ = row+1 - tJ;
			vertexs->push_back(p1 + sDir*i + tDir*tJ);
			vertexs->push_back(p1 + sDir*(i+1)+tDir*tJ);

			coords->push_back(osg::Vec2f(i, tJ)*uCoord);
			coords->push_back(osg::Vec2f(i+1, tJ)*uCoord);
		}
	}
	colors->push_back(osg::Vec4f(0.7, 0.7, 0.7, 1.0));
	osg::Vec3d nr = -sDir^tDir;
	nr.normalize();
	normals->push_back(nr);

	osg::Geometry* geometry = new osg::Geometry;
	geometry->setVertexArray(vertexs);
	geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUAD_STRIP, 0, vertexs->size()));
	geometry->setColorArray(colors);
	geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
	geometry->setTexCoordArray(0, coords);
	geometry->setNormalArray(normals);
	geometry->setNormalBinding(osg::Geometry::BIND_OVERALL);
	osg::Geode* geode = new osg::Geode;
	geode->addDrawable(geometry);
	geode->setNodeMask(MASK_OBJECT);
	geode->getOrCreateStateSet()->addUniform(new osg::Uniform("uIsSelect", false));
	geode->getOrCreateStateSet()->addUniform(new osg::Uniform("uTextureNum", 0));
	geode->getOrCreateStateSet()->addUniform(new osg::Uniform("uTexture0", 0));
	geode->getOrCreateStateSet()->addUniform(new osg::Uniform("uCoord", m_coord));
	return geode;
}
osg::Node* CViewerWidget::getInterNodeByScreen(float x, float y, osg::Camera* camera, int traversal)
{
	osg::Vec3d pos = getVec3ByScreen(x, y, camera);
	osg::Vec3d eyePos = camera->getInverseViewMatrix().getTrans();
	osg::Vec3d dir = pos - eyePos;
	dir.normalize();

	osg::ref_ptr<osg::LineSegment> ls = new osg::LineSegment(eyePos, eyePos + dir*MAXINT32);
	osgUtil::IntersectVisitor iv;
	iv.addLineSegment(ls);
	iv.setTraversalMask(traversal);
	for (oUInt i = 0; i < camera->getNumChildren(); i++)
	{
		camera->getChild(i)->accept(iv);
	}
	if (iv.hits())
	{
		osgUtil::Hit hit = iv.getHitList(ls).at(0);
		oUInt size = hit.getNodePath().size();
		return hit.getNodePath().at(size-1);
	}
	return NULL;
}
void CViewerWidget::mousePressEvent( QMouseEvent* event )
{
	m_buttonMask = event->buttons();
	switch(event->button())
	{
	case Qt::LeftButton:
		{
			osg::Node* node = getInterNodeByScreen(event->posF().x(), height()-event->posF().y(), getCamera(), MASK_OBJECT);
			if (node)
			{
				if (m_selectNode)
				{
					m_selectNode->getOrCreateStateSet()->getOrCreateUniform("uIsSelect", osg::Uniform::BOOL)->set(false);
				}
				m_selectNode = node;
				m_selectNode->getOrCreateStateSet()->getOrCreateUniform("uIsSelect", osg::Uniform::BOOL)->set(true);
			}
		}
		break;
	case Qt::RightButton:
		{
			m_lastPos = event->pos();
			if (m_selectNode)
			{
				m_selectNode->getOrCreateStateSet()->getOrCreateUniform("uIsSelect", osg::Uniform::BOOL)->set(false);
				m_selectNode = NULL;
			}
		}
		break;
	}
}

void CViewerWidget::mouseReleaseEvent( QMouseEvent* event )
{
	m_buttonMask = event->buttons();
}

void CViewerWidget::mouseMoveEvent( QMouseEvent* event )
{
	if (m_buttonMask&Qt::RightButton)
	{
		QPoint pos = event->pos();
		m_yaw += (pos.x() - m_lastPos.x())*0.001f;
		m_pitch += (pos.y() - m_lastPos.y())*0.001f;
		m_lastPos = pos;
		updateHouse();
	}
}

void CViewerWidget::wheelEvent( QWheelEvent* event )
{

}

void CViewerWidget::updateHouse()
{
	osg::Vec3f xDir = (osg::Matrix::translate(1.0, 0.0, 0.0)*osg::Matrix::rotate(m_yaw, osg::Vec3f(0.0, 0.0, 1.0))).getTrans();
	osg::Matrix mat = osg::Matrix::rotate(m_yaw, osg::Vec3f(0.0, 0.0, 1.0))*osg::Matrix::rotate(m_pitch, xDir);
	m_house->setMatrix(mat);
}

void CViewerWidget::setTexture( std::string file )
{
	if (m_selectNode)
	{
		osg::Texture2D* texture = new osg::Texture2D(osgDB::readImageFile(file));
		texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
		texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
		m_selectNode->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture);
		m_selectNode->getOrCreateStateSet()->getOrCreateUniform("uTextureNum", osg::Uniform::INT)->set(1);
	}
}

void CViewerWidget::setCoordS(float s)
{
	if (m_selectNode)
	{
		m_coord.x() = s;
		m_selectNode->getOrCreateStateSet()->getOrCreateUniform("uCoord", osg::Uniform::FLOAT_VEC2)->set(m_coord);
	}
}

void CViewerWidget::setCoordT(float t)
{
	if (m_selectNode)
	{
		m_coord.y() = t;
		m_selectNode->getOrCreateStateSet()->getOrCreateUniform("uCoord", osg::Uniform::FLOAT_VEC2)->set(m_coord);
	}
}

